package q1.project.log;

import java.time.LocalDateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 操作日志服务实现
 *
 * @author Q1 Team
 * @version 1.0
 */
@Service
public class OperationLogServiceImpl implements OperationLogService {

  private static final Logger log = LoggerFactory.getLogger(OperationLogServiceImpl.class);

  private final OperationLogDao operationLogDao;

  /** 构造函数，用于依赖注入和验证Bean是否被创建 */
  public OperationLogServiceImpl(OperationLogDao operationLogDao) {
    this.operationLogDao = operationLogDao;
    log.info("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
    log.info("操作日志服务实现类已初始化: {}", this.getClass().getName());
    log.info("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
  }

  /** 初始化后检查依赖 */
  @jakarta.annotation.PostConstruct
  public void init() {
    if (operationLogDao == null) {
      log.error("❌ OperationLogDao 未注入！无法保存操作日志。");
    } else {
      log.info("✓ OperationLogDao 已注入: {}", operationLogDao.getClass().getName());
    }
  }

  @Override
  @Async("operationLogExecutor")
  public void saveAsync(OperationLogEntity logEntity) {
    // 立即输出日志，确认异步方法被执行
    log.info("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
    log.info(
        "异步保存操作日志开始执行: thread={}, module={}, type={}, description={}, tenantId={}, userId={}",
        Thread.currentThread().getName(),
        logEntity.getModule(),
        logEntity.getType(),
        logEntity.getDescription(),
        logEntity.getTenantId(),
        logEntity.getUserId());

    try {
      // ✅ 租户上下文已通过 TenantContextTaskDecorator 自动传递
      // 从上下文获取租户ID（如果logEntity中没有）
      if (logEntity.getTenantId() == null || logEntity.getTenantId().isEmpty()) {
        String contextTenantId = q1.project.common.context.TenantContext.getTenantId();
        if (contextTenantId != null && !contextTenantId.isEmpty()) {
          logEntity.setTenantId(contextTenantId);
          log.debug("从租户上下文获取租户ID: {}", contextTenantId);
        } else {
          // ❌ 不再使用硬编码默认值
          log.error(
              "操作日志租户ID为空且无法从上下文获取: module={}, type={}",
              logEntity.getModule(),
              logEntity.getType());
          // 记录但不保存，避免数据混乱
          return;
        }
      }

      // 确保有ID
      if (logEntity.getId() == null || logEntity.getId().isEmpty()) {
        logEntity.setId(java.util.UUID.randomUUID().toString().replace("-", ""));
        log.debug("生成操作日志ID: id={}", logEntity.getId());
      }
      // 确保有创建时间
      if (logEntity.getCreateTime() == null) {
        logEntity.setCreateTime(java.time.LocalDateTime.now());
        log.debug("设置操作日志创建时间: createTime={}", logEntity.getCreateTime());
      }

      // 截断过长的字段，避免数据库错误
      if (logEntity.getBrowser() != null && logEntity.getBrowser().length() > 500) {
        log.warn("浏览器信息过长，将截断: 原始长度={}, 截断后长度=500", logEntity.getBrowser().length());
        logEntity.setBrowser(logEntity.getBrowser().substring(0, 500));
      }
      if (logEntity.getOs() != null && logEntity.getOs().length() > 500) {
        log.warn("操作系统信息过长，将截断: 原始长度={}, 截断后长度=500", logEntity.getOs().length());
        logEntity.setOs(logEntity.getOs().substring(0, 500));
      }
      if (logEntity.getUrl() != null && logEntity.getUrl().length() > 500) {
        log.warn("URL过长，将截断: 原始长度={}, 截断后长度=500", logEntity.getUrl().length());
        logEntity.setUrl(logEntity.getUrl().substring(0, 500));
      }
      if (logEntity.getMethod() != null && logEntity.getMethod().length() > 200) {
        log.warn("方法名过长，将截断: 原始长度={}, 截断后长度=200", logEntity.getMethod().length());
        logEntity.setMethod(logEntity.getMethod().substring(0, 200));
      }
      if (logEntity.getDescription() != null && logEntity.getDescription().length() > 500) {
        log.warn("描述过长，将截断: 原始长度={}, 截断后长度=500", logEntity.getDescription().length());
        logEntity.setDescription(logEntity.getDescription().substring(0, 500));
      }
      if (logEntity.getModule() != null && logEntity.getModule().length() > 50) {
        log.warn("模块名过长，将截断: 原始长度={}, 截断后长度=50", logEntity.getModule().length());
        logEntity.setModule(logEntity.getModule().substring(0, 50));
      }
      if (logEntity.getType() != null && logEntity.getType().length() > 20) {
        log.warn("类型过长，将截断: 原始长度={}, 截断后长度=20", logEntity.getType().length());
        logEntity.setType(logEntity.getType().substring(0, 20));
      }
      if (logEntity.getUsername() != null && logEntity.getUsername().length() > 50) {
        log.warn("用户名过长，将截断: 原始长度={}, 截断后长度=50", logEntity.getUsername().length());
        logEntity.setUsername(logEntity.getUsername().substring(0, 50));
      }
      if (logEntity.getIp() != null && logEntity.getIp().length() > 50) {
        log.warn("IP地址过长，将截断: 原始长度={}, 截断后长度=50", logEntity.getIp().length());
        logEntity.setIp(logEntity.getIp().substring(0, 50));
      }
      if (logEntity.getErrorMsg() != null && logEntity.getErrorMsg().length() > 2000) {
        log.warn("错误信息过长，将截断: 原始长度={}, 截断后长度=2000", logEntity.getErrorMsg().length());
        logEntity.setErrorMsg(logEntity.getErrorMsg().substring(0, 2000));
      }

      log.info(
          "准备保存到数据库: id={}, module={}, type={}, tenantId={}, userId={}",
          logEntity.getId(),
          logEntity.getModule(),
          logEntity.getType(),
          logEntity.getTenantId(),
          logEntity.getUserId());

      // 保存到数据库
      OperationLogEntity saved = operationLogDao.save(logEntity);

      log.info("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
      log.info(
          "✅ 操作日志保存成功: id={}, module={}, type={}, description={}, tenantId={}, userId={}, thread={}",
          saved.getId(),
          saved.getModule(),
          saved.getType(),
          saved.getDescription(),
          saved.getTenantId(),
          saved.getUserId(),
          Thread.currentThread().getName());
      log.info("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
    } catch (Exception e) {
      log.error("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
      log.error(
          "❌ 操作日志保存失败: module={}, type={}, description={}, tenantId={}, userId={}, thread={}, error={}",
          logEntity.getModule(),
          logEntity.getType(),
          logEntity.getDescription(),
          logEntity.getTenantId(),
          logEntity.getUserId(),
          Thread.currentThread().getName(),
          e.getMessage(),
          e);
      log.error("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
      // 异步方法中的异常需要被记录，但不能重新抛出（因为调用方已经返回）
      log.error("异步保存操作日志失败", e);
    }
  }

  @Override
  public Page<OperationLogEntity> getOperationLogs(String tenantId, Pageable pageable) {
    // 如果租户ID为空，查询所有日志（超管场景）
    if (tenantId == null || tenantId.isEmpty()) {
      // 使用 findAll 查询所有日志，Spring Data JPA 会自动处理排序
      // 注意：需要确保 pageable 中包含排序信息
      return operationLogDao.findAll(pageable);
    }
    return operationLogDao.findByTenantIdOrderByCreateTimeDesc(tenantId, pageable);
  }

  @Override
  public Page<OperationLogEntity> getOperationLogsByUser(String userId, Pageable pageable) {
    return operationLogDao.findByUserIdOrderByCreateTimeDesc(userId, pageable);
  }

  @Override
  public Page<OperationLogEntity> getOperationLogsByModule(String module, Pageable pageable) {
    return operationLogDao.findByModuleOrderByCreateTimeDesc(module, pageable);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void cleanExpiredLogs(int days) {
    LocalDateTime beforeTime = LocalDateTime.now().minusDays(days);
    operationLogDao.deleteByCreateTimeBefore(beforeTime);
    log.info("清理{}天前的操作日志完成", days);
  }
}
